package sisicotren.model.simulator;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Observable;
import java.util.LinkedList;

public class Queue <T> extends Observable {
	
	public Queue() {
		this(0);
	}
	
	public Queue(Integer max) {
		this.maxCapacity = max;
		this.queue = new LinkedList<T>();
		this.timeInQueue = new HashMap<T, Long>();
	}
	
	public Boolean isInfinite() {
		return this.maxCapacity == 0;
	}
	
	public Boolean push(T elem) {
		if(this.isInfinite() || this.maxCapacity < this.queue.size()) {
			this.timeInQueue.put(elem, java.lang.System.currentTimeMillis());
			this.queue.add(elem);
			this.setChanged();
			this.notifyObservers(new QueueNotification("add", this.queue.size()));
			// actualizo el valor del maximo.
			if(this.queue.size() > this.maxElementsInQueue)
				this.maxElementsInQueue  = this.queue.size();
			
			return true;
		}
		
		return false;
	}
	
	public T poll() {
		T e = this.queue.poll();
		this.setChanged();
		this.notifyObservers(new QueueNotification("pool", this.queue.size()));
		Long pushTime = this.timeInQueue.get(e);
		this.timeInQueue.put(e, java.lang.System.currentTimeMillis() - pushTime);
		return e;
	}
	
	public Integer getMaxElemensInQueue() {
		return this.maxElementsInQueue;
	}
	
	public Integer size() {
		return this.queue.size();
	}
	
	public Long getMaxTimeElementInQueue() {
		Collection <Long> times = this.timeInQueue.values();
		List<Long> sortedList = new ArrayList<Long>(times);
		Collections.sort(sortedList);
		
		// el primer elemento es el menor
		return sortedList.isEmpty() ? 0L : sortedList.iterator().next();
	}
	
	private java.util.Queue<T> queue;
	private int maxCapacity;
	private int maxElementsInQueue = 0;
	private Map<T, Long> timeInQueue;
}
